סריקה לעומק רכיבים אי-פריקים רכיבים קשירים היטב מיון טופולוגי פרק 3 ב- Kleinberg/Tardos פרק 3.3-5 ב- al Cormen et
קשירות נעיין שוב בבעיית הקשירות: ל- t? האם יש מסלול מ- s
קשירות נעיין שוב בבעיית הקשירות: ל- t? האם יש מסלול מ- s s t
כשלון הגישה החמדנית s t 3
כשלון הגישה החמדנית s t 3
תיקון s t כשנתקעים במבוי סתום, נבטל את הצעד האחרון שנכשל, וננסה כיוון התקדמות אחר. 4
תיקון s t כשנתקעים במבוי סתום, נבטל את הצעד האחרון שנכשל, וננסה כיוון התקדמות אחר. 4
תיקון s t כשנתקעים במבוי סתום, נבטל את הצעד האחרון שנכשל, וננסה כיוון התקדמות אחר. 4
תיקון s t כשנתקעים במבוי סתום, נבטל את הצעד האחרון שנכשל, וננסה כיוון התקדמות אחר. 4
תיקון s t כשנתקעים במבוי סתום, נבטל את הצעד האחרון שנכשל, וננסה כיוון התקדמות אחר. 4
תיקון s t כשנתקעים במבוי סתום, נבטל את הצעד האחרון שנכשל, וננסה כיוון התקדמות אחר. 4
תיקון s t כשנתקעים במבוי סתום, נבטל את הצעד האחרון שנכשל, וננסה כיוון התקדמות אחר. 4
תיקון s t כשנתקעים במבוי סתום, נבטל את הצעד האחרון שנכשל, וננסה כיוון התקדמות אחר. 4
connectivity(g,s,t) for each x V do pre[x], post[x], from[x] nil pre_c, post_c DFS(G,s) return pre[t] < DFS(G,x) pre[x] pre_c++ for each y Adj[x] do if pre[y] = then from[y] x DFS(G,y) end if end for post[x] post_c++ end DFS סריקה לעומק (DFS) בצעד הזה מגלים את x בצעד הזה נאמר שהקשת (x,y) נסרקה בצעד הזה חוזרים מ- x סדר הגילוי: pre[x] סדר החזרה: post[x] 5
סיבוכיות אתחול: O( V ) מבצעים DFS(G,x) לכל היותר פעם אחת לכל x. נחייב את הקריאה ל-( DFS(G,x על x. למעט הקריאות הרקורסיביות, DFS(G,x) עולה O()+O( Adj[x] ) סה כ: O( V ) + x V {O() + O( Adj[x] )} = O( V + E ) 6
סיווג הקשתות הקשתות הנסרקות נחלקות לארבעה סוגים. קשת שנסרקה (x,y) היא: קשת עץ, אם from[y] = x (כלומר, סריקתה גילתה את y). קשת קדימה, אם איננה קשת עץ, אבל y נתגלה בין גילוי x לחזרה מ- x. קשת אחורה, אם x נתגלה בין גילוי y לחזרה מ- y. קשת הצידה, אם האפשרויות האחרות לא נתקיימו. הגרף TDFS הנפרש על ידי קשתות העץ הוא עץ מכוון ששורשו s, והוא פורש את כל הצמתים הנגישים מ- s. 7
הדגמה המספרים על הקשתות: סדר הסריקה. זוגות המספרים על הצמתים: סדר הגילוי וסדר החזרה., 8, 3 3 3, 4 4,, 9 7 9 6 5 3 7, 4 8 6, 7 8, 6 5, קשתות עץ קשתות קדימה קשתות אחורה קשתות הצידה 9, 5 8
הערות אפשר להריץ את האלגוריתם על גרף לא מכוון. כל קשת {x,y} תיסרק בשני כיוונים: מ- x ל- y ומ- y ל- x. רק הסריקה הראשונה יכולה לגלות צומת חדש.. הוכיחו כי בסריקה לעומק של גרף לא מכוון אין קשתות הצידה. (הערה: בגרף לא מכוון אין הבדל בין קשתות קדימה וקשתות אחורה - שכנעו את עצמכם שכל הקשתות הללו נסרקות לראשונה בכיוון אחורה.). הוכיחו כי ב- G יש מעגל פשוט המכיל את s אםם בכל הרצת לפחות קשת אחת אחורה שנכנסת ל- s. מקבלים מ- s DFS 9
רכיבים אי פריקים הגדרה: נתון גרף לא מכוון.G=(V,E) יהי יחס שקילות על,E שמקיים x y אםם x = y או שיש מעגל פשוט שמכיל את x ו- y. תתי הגרף הנפרשים על ידי מחלקות השקילות של נקראים הרכיבים האי-פריקים של G. שימו לב: הרכיבים האי-פריקים זרים בקשתות, אבל לא בהכרח זרים בצמתים. הקלט: גרף לא מכוון G הפלט: חלוקה של G לרכיבים אי פריקים.
תכונות הגדרה: צומת x V נקרא צומת הפרדה אםם הסרתו מגדילה את מספר הרכיבים הקשירים של הגרף. קשת e E נקראת גשר אםם הסרתה מגדילה את מספר הרכיבים הקשירים של הגרף. גשר רכיב אי-פריק עם קשת אחת. צומת הפרדה חיתוך בין שני רכיבים אי-פריקים לא זרים. את הגרף שצמתיו הרכיבים יהי G גרף. נסמן ב-( bc(g האי-פריקים של G וצמתי ההפרדה של G וקשתותיו מחברות בין כל הזוגות של רכיב אי-פריק וצומת הפרדה שמוכל בו. אזי bc(g) הוא עץ.
הדגמה צומת הפרדה גשר
הדגמה צומת הפרדה גשר
הדגמה צומת הפרדה גשר
3 הדגמה
זיהוי צמתי הפרדה נריץ סריקה לעומק של גרף קשיר G החל מצומת s כלשהו. נתבונן בעץ המכוון. TDFS משפט: השורש s הוא צומת הפרדה אםם יש לו לפחות שני ילדים. כל צומת אחר x הוא צומת הפרדה אםם יש לו ילד y כך שבתת- העץ המושרש ב- y אין אף צומת שממנו קשת אחורה לאב-קדמון של x. 4
הוכחה אם ל- s ילד יחיד x, אזי הסרת s מותירה את תת-העץ המושרש ב- x. זהו תת-גרף קשיר של G, לכן s אינו צומת הפרדה. אם ל- s לפחות שני ילדים x ו- y, אזי הסרת s מותירה לפחות שני תתי- עצים המושרשים ב- x וב- y. נניח שיש קשת בין צומת u בתת-עץ אחד לצומת v בתת-העץ האחר. בה כ u נתגלה לפני להגיע ל- v, חייבים אזי בסריקה מ- u.(pre[u] < pre[v] (כלומר, v ולכן v באותו תת-העץ כמו u, וזו סתירה להנחת קיום הקשת. כלומר, תתי-העצים הללו הם רכיבים קשירים נבדלים, ולכן s צומת הפרדה. 5
הוכחה (המשך) יהי x צומת שאיננו s. אם יש ל- x ילד y שבתת-העץ המושרש בו אין אף צומת עם קשת אחורה לאב קדמון של x, אזי הסרת x מנתקת את תת-העץ המושרש ב- y משאר הגרף: על פי הנתון אין אף קשת מתת-העץ לצומת במסלול מ- s ל- x. בדומה לטיעון הקודם, גם אין קשת מתת-העץ המושרש ב- y לאיזשהו תת-עץ שאינו מכיל את y. שאר הגרף כולל לפחות צומת אחד, s, ולכן x צומת הפרדה. אחרת, גם אחרי הסרת x כל תת-עץ שמושרש בילד של x נותר ברכיב הקשיר של s. בוודאי כל הצמתים שאינם בתת-העץ המושרש ב- x נותרים ברכיב הקשיר של s. לכן מספר הרכיבים הקשירים לא עולה, ולכן x איננו צומת הפרדה. 6
הדגמה s 6 5 3 4 7 8 9 7
הדגמה s 6 5 3 4 7 8 9 7
הדגמה s 6 5 3 4 7 8 9 7
הדגמה s 6 5 3 4 7 8 9 7
הדגמה s 6 5 3 4 7 8 9 7
הדגמה s 6 5 3 4 7 8 9 7
הדגמה s 6 5 3 4 7 8 9 7
מציאת צמתי הפרדה נחשב לכל צומת x ערך,low[x] שהוא המינימום של pre[z] על כל z שניתן להגיע אליו מתת-העץ המושרש ב- x תוך שימוש בקשת אחורה אחת לכל היותר. צומת x שאיננו s הוא צומת הפרדה אםם יש ל- x ילד y עבורו מתקיים pre[x].low[y] לכל צומת x נחזיק ערך,art[x] שיאותחל ל- no וישונה ל- yes אםם נזהה את x כצומת הפרדה. הערה: קשת {x,y} היא גשר אםם היא קשת עץ (x,y) (בחרנו כיוון בה כ), ו-[ pre[x.low[y] > 8
6 הדגמה בכחול: ערך low והקשת שקבעה. 5 3 4 7 8 9 9
הדגמה 6 בכחול: ערך low והקשת שקבעה. 5 3 4 7 8 9 9
הדגמה 6 בכחול: ערך low והקשת שקבעה. 5 3 4 7 8 9 9
הדגמה 6 בכחול: ערך low והקשת שקבעה. 5 3 4 7 8 9 9
הדגמה 6 בכחול: ערך low והקשת שקבעה. 5 3 4 7 8 9 9
הדגמה 6 בכחול: ערך low והקשת שקבעה. 5 3 4 7 8 9 9
הדגמה 6 בכחול: ערך low והקשת שקבעה. 5 3 4 7 8 9 9
הדגמה 6 בכחול: ערך low והקשת שקבעה. 5 3 4 7 8 9 9
הדגמה 6 בכחול: ערך low והקשת שקבעה. 5 3 4 7 8 9 9
הדגמה 6 בכחול: ערך low והקשת שקבעה. 5 3 4 7 8 8 9 9
הדגמה 6 בכחול: ערך low והקשת שקבעה. 5 3 4 7 8 8 9 9
הדגמה 6 בכחול: ערך low והקשת שקבעה. 3 4 7 5 7 8 8 9 9
הדגמה 6 בכחול: ערך low והקשת שקבעה. 3 4 7 5 7 9 8 8 9 9
הדגמה 6 בכחול: ערך low והקשת שקבעה. 3 4 7 5 7 9 9 8 8 9 9
DFS_low(G,x) low[x] pre[x] pre_c++ for each y Adj[x] do if pre[y] = then DFS_low(G,y) if low[y] < low[x] then low[x] low[y] if low[y] pre[x] then art[x] yes else if pre[y] < low[x] then low[x] pre[y] end if end for end DFS_low חישוב low עבור צומת שאיננו השורש במקרה זה y ילד של x מתת-העץ המושרש ב- y יש קשת אחורה לאב קדמון של low[x] הנוכחי במקרה זה y אב קדמון של x
סימון הרכיבים האי-פריקים for each y Adj[x] do if {x,y} לא סרקנו עדיין את then push({x,y},stack) נחזיק מחסנית של קשתות זה מונה של מספר הרכיבים את הלולאה של שליפת קשתות מהמחסנית צריך לבצע גם עבור כל ילד y של השורש s. שימו לב: ייתכן של- x יש מספר ילדים שיזהו אותו כצומת הפרדה, ואז כל ילד כזה יגרום לשליפת רכיב אי-פריק. if pre[y] = then... if low[y] pre[x] then art[x] yes bcc_c++ repeat e pop(stack) bcc[e] bcc_c while e {x,y} end if... end if end for
סיבוכיות הסריקה לעומק לוקחת O( V + E ) זמן. השינויים לחישוב low לא משנים את הסיבוכיות. לכל קשת מבצעים ()O פעולות מחסנית. סה כ סיבוכיות הזמן: O( V + E ) סיבוכיות המקום: O( V + E )
תרגיל בית הוכיחו שבכל פעם שמבצעים את לולאת repeat אכן קבוצת הקשתות הנשלפת מהמחסנית היא רכיב אי- פריק. 3
רכיבים קשירים היטב הגדרה: נתון גרף מכוון.G=(V,E) יהי יחס שקילות על V, שמקיים x y אםם יש מסלול מכוון מ- x ל- y וגם מ- y ל- x. תתי הגרף הנפרשים על ידי מחלקות השקילות של נקראים הרכיבים הקשירים היטב של G. שימו לב: תיתכנה קשתות של G שאין כלולות בשום רכיב קשיר היטב. הקלט: גרף מכוון G. הפלט: חלוקה של G לרכיבים קשירים היטב. 4
5 הדגמה
5 הדגמה
KS(G) for each x V do post[x], from[x] nil, scc[x] post_c, scc_c for each x V do if post[x] = then DFS(G,x) end for sort(v,-post) for each x V do if scc[x] = then DFS_scc(G T,x) scc_c++ end if end for end KS אלגוריתם Kosaraju-Sharir הערך scc[x] יציין את מספר הרכיב אליו שייך x. נמיין את V בסדר post יורד הגרף G T מתקבל מ- G על ידי הפיכת כל הקשתות. 6
, 7 קשתות עץ קשתות קדימה קשתות אחורה קשתות הצידה 7, 4, 6 8 6, 5 7 9 4, 3, 4 3 5 6 הדגמה: תוצאות DFS, 3 5, המספרים על הקשתות: סדר הסריקה. זוגות המספרים על הצמתים: סדר הגילוי וסדר החזרה. 7
איסוף רכיב קשיר היטב DFS_scc(G,x) scc[x] scc_c for each y Adj[x] do if scc[y] = then DFS_scc(G,y) end for end DFS_scc 8
7, 3 5 3 קשתות עץ קשתות קדימה קשתות אחורה קשתות הצידה, 4 63, 4 5, 6 7, 5 5, 7 הדגמה: תוצאות DFS_scc 7 9 8 3 4, 4 6, 6 המספרים על הקשתות: סדר הסריקה. זוגות המספרים על הצמתים: סדר הגילוי וסדר החזרה. באדום: סדר החזרה ב- DFS 9
הוכחת נכונות נתבונן בלולאה של הרצת DFS על G. אבחנה: הגרף הנפרש על ידי קשתות העץ הוא אוסף של עצים מכוונים זרים הפורשים יחד את.V(G) (כל קריאה מהפרוצדורה עץ מושרש ב- x.) מייצרת ל-( DFS(G,x KS הגדרה: לכל x V נסמן ב-( φ(x את הצומת בעל ערך post המירבי מבין כל הצמתים הנגישים מ- x ב- G. לב: φ(x) φ(φ(x)) = (מדוע?) שימו טענה: ב- G יש מסלול מכוון מ-( φ(x ל- x ולכן x ו-( φ(x באותו רכיב קשיר היטב. 3
6, 7 3, 3 הדגמה: חישוב φ קשתות עץ קשתות קדימה קשתות אחורה קשתות הצידה 7, 7 5, 7,,, 4, 7 זוגות המספרים על הצמתים: סדר החזרה וערך φ. 3
הוכחת נכונות (המשך) הוכחה: אם φ(x) = x אז בוודאי הטענה נכונה. אם חזרנו כבר מ-( φ(x לפני שגילינו את x אז post[x],post[φ(x)] < וזו סתירה להגדרת.φ(x) נניח שגילינו את x לפני שגילינו את.φ(x) אזי יהי z הצומת האחרון במסלול מ- x ל-( φ(x שנתגלה לפני או בזמן גילוי x. יש כזה כי x כזה. כל הצמתים בקטע המסלול מ- z ל-( φ(x עדיין לא נתגלו בזמן גילוי z. לכן כולם, בפרט φ(x) יתגלו בין גילוי z לחזרה מ- z. לכן post[z] post[φ(x)] < וזו סתירה להגדרה של,φ(x) כי z נגיש מ- x. לכן, האפשרות היחידה היא ש- x נתגלה בין גילוי φ(x) לבין החזרה מ-( φ(x, כלומר, x נמצא בתת-העץ המושרש ב-( φ(x, ולכן יש מסלול מכוון מ-( φ(x ל- x. 3
הוכחת נכונות (המשך) מסקנה: שני צמתים x,y נמצאים באותו רכיב קשיר היטב אםם φ(y).φ(x) = הוכחה: כל הצמתים באותו רכיב נגישים זה מזה, ולכן לכולם אותו ערך φ. מצד שני, x ו-( φ(x באותו רכיב וכך גם y ו-( φ(y. לכן, אם φ(y),φ(x) = אז x,y באותו רכיב. 33
הוכחת נכונות (המשך) עכשיו נתבונן בקריאה ל-( x, DFS_scc(G T הקריאות הקודמות (אם היו) ל- DFS_scc לא גילו את x, ולכן ב- G T אין אף מסלול מצומת שנתגלה בקריאות הקודמות ל- x, כלומר ב- G אין אף מסלול מ- x לצומת שנתגלה בקריאות הקודמות. אבל, קבוצת הצמתים שנתגלתה בקריאות הללו כוללת את כל הצמתים עם ערך post מ- DFS הגדול מ-[ post[x ולכן.φ(x) = x הצמתים המתגלים בקריאה ל-( x, DFS_scc(G T הם בדיוק הצמתים שנגישים ב- G T מ- x. לכל צומת כזה y יש ב- G מסלול מ- y ל- x. אבל x בעל ערך post המירבי מבין כל הצמתים שנותרו, כך ש- x.φ(y) = כלומר, הקריאה ל-( x, DFS_scc(G T מסמנת את הרכיב הקשיר היטב של x. 34